package org.jiucheng.magpiebridge.client.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.jiucheng.magpiebridge.client.util.ClientCfg;
import org.jiucheng.magpiebridge.client.util.ServerInfo;
import org.jiucheng.magpiebridge.transfer.aio.TransferAttachment;
import org.jiucheng.magpiebridge.util.Cfg;

/**
 * 
 * @author jiucheng
 *
 */
public class Client {
	private static final ScheduledExecutorService schedule = Executors.newScheduledThreadPool(2);
	
	public static void main(String[] args) throws IOException, InterruptedException {
	    Cfg.buildBaseDir(Client.class);
		Cfg.loadProperties();
		
		final ClientAttachment attachment = new ClientAttachment();
		startup(attachment);
		schedule(attachment);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                shutdown(attachment);
            }
        });
	}
	
    private static void schedule(final ClientAttachment clientAttachment) {
        // 重连
        schedule.scheduleAtFixedRate(new Runnable() {
            public void run() {
                if (clientAttachment.isFailed()) {
                    try {
                        startup(clientAttachment);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, 60, 60, TimeUnit.SECONDS);
        // 心跳
        schedule.scheduleWithFixedDelay(new Runnable() {
            public void run() {
            	if (!clientAttachment.isFailed()) {
            		clientAttachment.heartbeat();
            	}
            }
        }, 30L, 30L, TimeUnit.SECONDS);
    }
	
	public static void startup(final ClientAttachment attachment) throws IOException {
		ConcurrentHashMap<Integer, TransferAttachment> tas = attachment.getTransferAttachments();
		Enumeration<Integer> uris = tas.keys();
		if (uris != null) {
			while (uris.hasMoreElements()) {
				Integer uri = uris.nextElement();
				TransferAttachment ta = tas.remove(uri);
				if (ta != null) {
					ta.disconnect();
				}
			}
		}
		ServerInfo serverInfo = ClientCfg.getServerInfo();
		if (serverInfo == null) {
		    return;
		}
		attachment.setServerInfo(serverInfo);
        AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
        client.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        client.setOption(StandardSocketOptions.SO_RCVBUF, 8 * 1024 * 1024);
        attachment.setClient(client);
        attachment.setFailed(false);
        client.connect(new InetSocketAddress(attachment.getServerInfo().getIp(), attachment.getServerInfo().getPort()),
                attachment, attachment.getClientEstablishmentCompletionHandler());
	}
	
    public static void shutdown(ClientAttachment clientAttachment) {
        schedule.shutdownNow();
        clientAttachment.close();
    }
}
